package completableFuture

import (
	"errors"
	"fmt"
	"sync"
)

// CompletableFuture 类型的结构体
type CompletableFuture struct {
	// 结果通道
	Result chan any
	// 错误通道
	Error chan error
	// 保存结果（用于 ThenApply 方法中入参）
	SuccessResult any
	// 保存错误（用于 ThenApply 方法判断）
	ErrorResult error
	// 是否需要加锁（等待用于 ThenApply 方法获取入参时能拿到结果）
	lock bool
	// 用于获取保存值的读写锁（针对读多写少的这种场景，尽量不使用互斥锁）
	rwlock sync.RWMutex
}

// GoCompletableFuture 创建一个新的 CompletableFuture
// @param isLock bool 是否需要加读写锁用于结果值获取。为空时默认不加
func GoCompletableFuture(isLock ...bool) *CompletableFuture {
	c := &CompletableFuture{
		Result: make(chan any),
		Error:  make(chan error),
	}
	// 设置是否需要加读写锁用于结果值获取。默认不加
	if isLock != nil {
		c.lock = isLock[0]
	} else {
		c.lock = false
	}
	return c
}

// SupplyAsync 通过【结构体方法】的形式，将指定的函数作为 goroutine 执行，并将结果传递给 CompletableFuture，来实现 java 中 CompletableFuture#supplyAsync 的效果
func (f *CompletableFuture) SupplyAsync(fn func(parm interface{}) (any, error), param any) *CompletableFuture {
	// 加写锁
	if f.lock {
		f.rwlock.Lock()
	}
	go func() {
		defer close(f.Error)
		defer close(f.Result)
		result, err := fn(param)
		if err != nil {
			// 只有加锁的协程需要保存结果值（等待用于 ThenApply 方法获取入参时能拿到结果）
			if f.lock {
				f.ErrorResult = err
				f.rwlock.Unlock()
			}
			f.Error <- err
		} else {
			// 只有加锁的协程需要保存结果值（等待用于 ThenApply 方法获取入参时能拿到结果）
			if f.lock {
				f.SuccessResult = result
				f.rwlock.Unlock()
			}
			f.Result <- result
		}
	}()
	return f
}

// ThenApply 在 CompletableFuture 上应用转换函数，并返回一个新的 CompletableFuture
func (f *CompletableFuture) ThenApply(fn func(param any) (any, error)) *CompletableFuture {
	result := GoCompletableFuture()
	// 如果被依赖协程没有设置加锁，不允许该函数逻辑执行，直接输出错误并打印控制台
	if f.lock != true {
		go func() {
			fmt.Printf("\033[1;31;40m%s\033[0m\n", "The dependent goroutine parameters are set incorrectly,require a read-write lock to be flagged")
			result.Error <- errors.New("被依赖协程参数设置不正确，需要标记使用读写锁")
		}()
		return result
	}
	go func() {
		err := f.getErrorResult()
		if err != nil {
			result.Error <- err
		} else {
			value := f.getSuccessResult()
			newValue, newErr := fn(value)
			if newErr != nil {
				result.Error <- newErr
			} else {
				result.Result <- newValue
			}
		}
	}()
	return result
}

// Get 阻塞等待 CompletableFuture 的结果并返回
func (f *CompletableFuture) Get() (any, error) {
	select {
	case result := <-f.Result:
		return result, nil
	case err := <-f.Error:
		return nil, err
	}
}

// 获取成功结果
func (f *CompletableFuture) getSuccessResult() any {
	// 尝试加读锁，直到成功
	for {
		if f.rwlock.TryRLock() {
			result := f.SuccessResult
			// 解读锁
			f.rwlock.RUnlock()
			return result
		}
	}
}

// 获取失败结果
func (f *CompletableFuture) getErrorResult() error {
	// 尝试加读锁，直到成功
	for {
		if f.rwlock.TryRLock() {
			result := f.ErrorResult
			// 解读锁
			f.rwlock.RUnlock()
			return result
		}
	}
}
